package cn.virens.web.components.weixin.session.standard;

import java.io.Serializable;
import java.time.Duration;
import java.time.Instant;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

import cn.virens.exception.APIException;
import cn.virens.web.components.weixin.session.VirWxSession;

public class WxStandardSession implements VirWxSession, Serializable {
	private static final long serialVersionUID = 9053075941976708978L;

	private final String sessionId;

	private Instant creationTime;
	private Instant lastAccessedTime;
	private Duration maxInactiveInterval;

	private Map<String, Serializable> attributes = new ConcurrentHashMap<>();

	public WxStandardSession(String sessionId) {
		this.sessionId = sessionId;
	}

	@Override
	public String getSessionId() {
		return sessionId;
	}

	@Override
	public Instant getCreationTime() {
		return creationTime;
	}

	@Override
	public Instant getLastAccessedTime() {
		return lastAccessedTime;
	}

	@Override
	public Duration getMaxInactiveInterval() {
		return maxInactiveInterval;
	}

	@Override
	public Object getAttribute(String name) {
		return attributes.get(name);
	}

	@Override
	public Enumeration<String> getAttributeNames() {
		return Collections.enumeration(attributes.keySet());
	}

	@Override
	public void setAttribute(String name, Object value) {
		if (value instanceof Serializable) {
			this.attributes.put(name, (Serializable) value);
		} else if (value != null) { throw new APIException("SerializableError", "参数类必须是Serializable的实现类"); }
	}

	@Override
	public void removeAttribute(String name) {
		this.attributes.remove(name);
	}

	@Override
	public void invalidate() {
		this.lastAccessedTime = null;
	}

	@Override
	public boolean isExpired() {
		if (lastAccessedTime == null) { return true; }
		if (maxInactiveInterval.isNegative()) { return false; }

		Instant now = Instant.now();
		Instant expired = now.minus(maxInactiveInterval);

		return lastAccessedTime.isBefore(expired);
	}

	public void setCreationTime(Instant creationTime) {
		this.creationTime = creationTime;
	}

	public void setLastAccessedTime(Instant lastAccessedTime) {
		this.lastAccessedTime = lastAccessedTime;
	}

	public void setMaxInactiveInterval(Duration maxInactiveInterval) {
		this.maxInactiveInterval = maxInactiveInterval;
	}

	@Override
	public int hashCode() {
		return Objects.hashCode(sessionId);
	}

	@Override
	public boolean equals(Object obj) {
		return this.hashCode() == Objects.hashCode(obj);
	}

}
